#pragma once

#include "db_base.h"
#include <mariadb/mysql.h>
#include <unistd.h>

#include <memory>
#include <mutex>
#include <string_view>


enum class MysqlError 
{                     
    Success = 0,      
    InitLibraryFail, 
    InitThreadFail,
    InitFail,
    ConnectFail,
    QueryFail,
    InsertFail,
    UpdateFail,
    DeleteFail,
    CharacterSetError,
};


class MysqlQueryResult final : public DBQueryResult
{
public:
    MysqlQueryResult(MYSQL_RES *);
    const std::vector<std::string_view> &column_names() const override;
    // int column_index(std::string_view column_name) const override;
    int row_count() const override;
    const std::vector<DBRow> &result() const override;
private:
    void parse_field(MYSQL_RES *);
    void parse_result(MYSQL_RES *);
};


class MysqlException final : public DBException
{
    static std::unordered_map<MysqlError, const char *> mysql_error_msgs_;
public:
    using DBException::DBException;
    MysqlException(MysqlError error_no)
        : MysqlException(mysql_error_msgs_[error_no])
    {
    }
    virtual ~MysqlException()
    {}
};

struct MysqlLogin
{
    std::string host;
    uint16_t port;
    std::string username;
    std::string passwd;
    std::string schema;
};


class MysqlClient final: public DBClient
{
public:
    MysqlClient(std::string_view host, 
                uint16_t port,
                std::string_view username,
                std::string_view passwd,
                std::string_view schema = "");
    ~MysqlClient() override;
    void query(std::string_view sql) override;
    const std::shared_ptr<DBQueryResult> result() const override;
private:
    MYSQL *conn_;
    std::shared_ptr<MysqlQueryResult> result_ptr_;
    static std::unordered_map<pid_t, int> thread_client_count_;
    static int client_count_;
    static std::mutex client_count_mutex_;
private:
    static void init();
    static void destroy();
};
